/**
 * 
 */
package com.xpec.c4.game.cronjob;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import com.xpec.c4.game.utility.GameUtility;

/**
 * 以 cron job 為核心的定時處理機制, 可以在每週或每天的任何時間點執行指定的 task
 * 
 * @author TW15010
 */
public class CronJobManager {
	/** log4j object */
	private static final Log log = LogFactory.getLog(CronJobManager.class);

	/**
	 * 從 job detail 中取出要放到 basic service module 中執行的物件的 key
	 */
	public static final String TASK_OBJECT_KEY = "taskObject";

	/**
	 * 唯一實體
	 */
	private static CronJobManager instance;

	/**
	 * 執行 job 的定時器核心
	 */
	private Scheduler cronScheduler;

	public static void initial() {
		if (instance != null) {
			return;
		}

		instance = new CronJobManager();
	}

	private CronJobManager() {
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		try {
			cronScheduler = schedulerFactory.getScheduler();
			cronScheduler.start();
		} catch (SchedulerException e) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName(), e);
			}
		}
	}

	public static CronJobManager getInstance() {
		return instance;
	}

	/**
	 * 註冊 cron job
	 * 
	 * @param cronTask
	 *            task object
	 * @param cronExpressions
	 *            cron job 的執行時間表示式<br>
	 *            "0 07 16 * * ?" 每天 16:07 執行一次<br>
	 *            "0/10 * * * * ?" 從每分鐘的零秒開始，每10秒執行一次<br>
	 *            "0 32/60 * * * ?" 每小時的 32 分開始，每60分鐘執行一次<br>
	 *            "0 8/10 * * * ?" 每小時的 8 分開始，每10分鐘執行一次<br>
	 *            "0 * * * * ?" 每分鐘執行一次<br>
	 * @return
	 */
	public boolean registerJob(CronTaskTimer cronTask, String cronExpressions) {
		if (cronTask == null) {
			return false;
		}

		if (!GameUtility.isHaveString(cronExpressions)) {
			return false;
		}

		// 產生一個 job
		JobDetail jobDetail = JobBuilder.newJob(CronTaskExecuteJob.class).build();
		jobDetail.getJobDataMap().put(TASK_OBJECT_KEY, cronTask);

		// 產生定時觸發器
		CronTrigger cronTrigger = TriggerBuilder.newTrigger()
				.withSchedule(CronScheduleBuilder.cronSchedule(cronExpressions)).build();

		// 註冊 job
		try {
			cronScheduler.scheduleJob(jobDetail, cronTrigger);
		} catch (SchedulerException e) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName(), e);
			}

			return false;
		}

		// 將 key 寫回 task 中, 便於後續使用
		JobKey jobKey = jobDetail.getKey();
		cronTask.setJobKey(jobKey);

		return true;
	}

	/**
	 * 將一個 job 清除
	 * 
	 * @param cronTaskTimer
	 *            task object
	 * @return
	 */
	public boolean unregisterJob(CronTaskTimer cronTaskTimer) {
		if (cronTaskTimer.getJobKey() == null) {
			return false;
		}

		boolean res = false;
		try {
			res = cronScheduler.deleteJob(cronTaskTimer.getJobKey());
		} catch (SchedulerException e) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName(), e);
			}
		}

		if (res) {
			cronTaskTimer.setJobKey(null);
		}

		return res;
	}
}